package github.sf.fw.tools.db.impl.mysql;

import com.alibaba.druid.DbType;
import com.alibaba.druid.sql.builder.SQLBuilderFactory;
import com.alibaba.druid.sql.builder.SQLSelectBuilder;
import github.sf.fw.tools.db.DSProperty;
import github.sf.fw.tools.db.QueryFilter;
import github.sf.fw.tools.db.connector.JdbcConnector;
import github.sf.fw.tools.db.impl.RdbmsDataSourceMeta;
import github.sf.fw.tools.db.model.ColumnInfo;
import github.sf.fw.tools.db.model.TableInfo;
import github.sf.fw.tools.db.model.DataBaseInfo;
import github.sf.fw.tools.db.model.ResultData;
import github.sf.fw.tools.db.model.ResultRow;

import java.util.ArrayList;
import java.util.List;

public class MysqlDataSourceMeta extends RdbmsDataSourceMeta {

    private final List<DataBaseInfo> dataBaseInfos = new ArrayList<>();

    private JdbcConnector jdbcConnector;

    public MysqlDataSourceMeta(DSProperty dsProperty) {
        super(dsProperty);
    }

    public MysqlDataSourceMeta(DSProperty dsProperty, QueryFilter<String> dbFilter) {
        super(dsProperty, dbFilter);
    }

    @Override
    public DataBaseInfo getTableList(String schema) {
        jdbcConnector = getConnector();
        List<ResultRow> resultRows = queryTables(jdbcConnector, schema);
        List<TableInfo> tableInfoList = new ArrayList<>();
        for (ResultRow resultRow : resultRows) {
            TableInfo tableInfo = getTableInfo(schema, resultRow);
            tableInfoList.add(tableInfo);
        }
//        dbHelper.close();
        DataBaseInfo dataBaseInfo = new DataBaseInfo();
        dataBaseInfo.setName(schema);
        dataBaseInfo.setTableInfoList(tableInfoList);
        return dataBaseInfo;
    }

    private TableInfo getTableInfo(String schema, ResultRow resultRow) {
        TableInfo tableInfo = new TableInfo();
        for (ResultData resultDatum : resultRow) {
            if (MysqlConstants.COL_TABLE_NAME.equals(resultDatum.getColumnName())) {
                tableInfo.setName((String) resultDatum.getColumnValue());
                SQLSelectBuilder selectSQLBuilder = SQLBuilderFactory.createSelectSQLBuilder(DbType.mysql);
                String originalSql = selectSQLBuilder.select("*").from(concat(schema, tableInfo.getName())).toString();
                tableInfo.getTableExtraInfo().setQuerySql(originalSql);
            }
            if (MysqlConstants.COL_TABLE_COMMENT.equals(resultDatum.getColumnName())) {
                tableInfo.setComment((String) resultDatum.getColumnValue());
            }
        }
        return tableInfo;
    }

    public void loadColumnInfo(DataBaseInfo dataBaseInfo) {
        jdbcConnector = getConnector();
        for (TableInfo tableInfo : dataBaseInfo.getTableInfoList()) {
//            String querySql = StrUtil.format(MysqlConstants.QUERY_COLUMN_INFO, dataBaseInfo.getName(), tableInfo.getName());
            tableInfo.setDbName(dataBaseInfo.getName());
            loadColumnInfo(tableInfo);
        }
    }

    public void loadColumnInfo(TableInfo tableInfo) {
        jdbcConnector = getConnector();
        tableInfo.setColumnInfoList(new ArrayList<>());
        List<ResultRow> colResults = queryColumns(jdbcConnector, tableInfo.getDbName(), tableInfo.getName());
        for (ResultRow colResult : colResults) {
            ColumnInfo columnInfo = new ColumnInfo();
            for (ResultData resultData : colResult) {
                if (MysqlConstants.COL_COLUMN_NAME.equals(resultData.getColumnName())) {
                    columnInfo.setName(resultData.getColumnValueAsString());
                }
                if (MysqlConstants.COL_COLUMN_TYPE.equals(resultData.getColumnName())) {
                    columnInfo.setType(resultData.getColumnValueAsString());
                }

                if (MysqlConstants.COL_COLUMN_CHARSET.equals(resultData.getColumnName())) {
                    columnInfo.setCharacterSetName(resultData.getColumnValueAsString());
                }

                if (MysqlConstants.COL_COLUMN_COLUMN_KEY.equals(resultData.getColumnName())) {
                    columnInfo.setColumnKey(resultData.getColumnValueAsString());
                }
                if (MysqlConstants.COL_COLUMN_COMMENT.equals(resultData.getColumnName())) {
                    columnInfo.setComment(resultData.getColumnValueAsString());
                }
            }
            tableInfo.getColumnInfoList().add(columnInfo);
        }
    }

    private void loadTableInfo(JdbcConnector jdbcConnector) {
        for (DataBaseInfo dataBaseInfo : dataBaseInfos) {
            String libraryName = dataBaseInfo.getName();
            List<ResultRow> resultRows = queryTables(jdbcConnector, libraryName);
            for (ResultRow resultRow : resultRows) {
                TableInfo tableInfo = getTableInfo(libraryName, resultRow);
                dataBaseInfo.getTableInfoList().add(tableInfo);
            }
        }
    }

    private void loadDatabase(JdbcConnector jdbcConnector) {
        List<ResultRow> resultRows = doQuery(jdbcConnector, MysqlConstants.SHOW_ALL_DATABASE_CMD, null);
        for (ResultRow resultRow : resultRows) {
            DataBaseInfo dataBaseInfo = new DataBaseInfo();
            boolean add = false;
            ResultData resultDatum = resultRow.get(0);
            if (resultDatum == null) {
                continue;
            }
            String val = (String) resultDatum.getColumnValue();
            if (dbFilter != null) {
                if (dbFilter.isSkip(val)) {
                    continue;
                }
            }
            add = true;
            dataBaseInfo.setName((String) resultDatum.getColumnValue());
            dataBaseInfos.add(dataBaseInfo);
        }
    }

    public String concat(String schema, String table) {
        String collect = ".";
        return schema + collect + table;
    }

    @Override
    public List<DataBaseInfo> getDBList() {
        jdbcConnector = getConnector();
        loadDatabase(jdbcConnector);
        for (DataBaseInfo dataBaseInfo : dataBaseInfos) {
            List<ResultRow> resultRows = doQuery(jdbcConnector, MysqlConstants.QUERY_TABLE_COUNT_OF_SCHEMA, new Object[]{dataBaseInfo.getName()});
            Object columnValue = resultRows.get(0).get(0).getColumnValue();
            dataBaseInfo.setTableCount(Math.toIntExact((Long) columnValue));
        }
        return dataBaseInfos;
    }

    public JdbcConnector getConnector() {
        if (jdbcConnector == null) {
            jdbcConnector = JdbcConnector.getInst(dsProperty);
        }
        return jdbcConnector;
    }

    public void close() {
        if (jdbcConnector != null) {
            jdbcConnector.close();
        }
    }
}
